﻿using System;
using System.Collections.Generic;
using System.Reflection;
using net.entity.framework.common;
using net.entity.framework.query;

namespace net.entity.framework {
    public static class EntityInvoker {
        public static TEntityRef InvokeEntityRef<TEntityRef>(Entity entity) where TEntityRef : EntityRef{
            return (TEntityRef) InvokeEntityRef(entity.ObjectType, entity.Id, entity.TypeId, entity.Revision);
        }

        public static T InvokeEntityRef<T>(Type entityRefType, int id, int typeId, int revision,
                                           QueryContext queryContext) where T : EntityRef {
            return (T) InvokeEntityRef(entityRefType, id, typeId, revision, queryContext);
        }

        public static EntityRef InvokeEntityRef(Type entityRefType, int id, int typeId, int revision) {
            return InvokeEntityRef(entityRefType, id, typeId, 0, null);
        }

        /// <summary>
        /// Invoke EntityRef
        /// </summary>
        /// <param name="entityRefType"></param>
        /// <param name="id"></param>
        /// <param name="typeId"></param>
        /// <param name="revision"></param>
        /// <param name="queryContext">for Contextfull invocation</param>
        /// <returns></returns>
        public static EntityRef InvokeEntityRef(Type entityRefType, int id, int typeId, int revision,
                                                QueryContext queryContext) {
            var args = queryContext == null
                           ? new List<object> {id, typeId, revision}
                           : new List<object> {id, typeId, revision, queryContext};

            var constructor = entityRefType.GetConstructorInfo(args, BindingFlags.Instance | BindingFlags.Public,
                                                               true);
            return (EntityRef) constructor.Invoke(args.ToArray());
        }


        public static T InvokeEntity<T>(Type entityType, List<Object> args, string creator, DateTime timeStamp)
            where T : Entity {
            return (T) InvokeEntity(entityType, args, creator, timeStamp);
        }

        public static Entity InvokeEntity(Type entityType, List<Object> args, string creator, DateTime timeStamp) {
            var method = entityType.GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
            return (Entity) method.Invoke(ReflectUtil.voidObj, new object[] {entityType, args, creator, timeStamp});
        }
    }
}